//DESCRIPTION:按选择的段落样式精确识别 DANGER/WARNING/CAUTION/NOTE 与“下划线”段，并在“下划线段”段首插入各自自定义前缀（可按对象样式筛选；稳健逆序写入）
#target "indesign"
(function () {
    if (app.documents.length === 0) { alert("请先打开一个文档。"); return; }
    var doc = app.activeDocument;

    // =============== 收集样式（含组路径） ===============
    function collectParaStyles(doc) {
        var names = [], map = {};
        function walk(container, prefix) {
            var styles = container.paragraphStyles;
            for (var i=0; i<styles.length; i++) {
                var st = styles[i];
                if (st.name === "[No Paragraph Style]") continue;
                var full = prefix ? (prefix + "/" + st.name) : st.name;
                names.push(full);
                map[full] = st;
            }
            var groups = container.paragraphStyleGroups;
            for (var j=0; j<groups.length; j++) {
                var g = groups[j];
                var newPrefix = prefix ? (prefix + "/" + g.name) : g.name;
                walk(g, newPrefix);
            }
        }
        walk(doc, "");
        names.sort(function(a,b){ a=a.toUpperCase(); b=b.toUpperCase(); return a<b?-1:(a>b?1:0); });
        return {names:names, map:map};
    }

    function collectObjectStyles(doc) {
        var names = [], map = {};
        function walk(container, prefix) {
            var sts = container.objectStyles;
            for (var i=0; i<sts.length; i++) {
                var st = sts[i];
                var full = prefix ? (prefix + "/" + st.name) : st.name;
                names.push(full); map[full] = st;
            }
            var grps = container.objectStyleGroups;
            for (var j=0; j<grps.length; j++) {
                var g = grps[j];
                var newPrefix = prefix ? (prefix + "/" + g.name) : g.name;
                walk(g, newPrefix);
            }
        }
        walk(doc, "");
        names.sort(function(a,b){ a=a.toUpperCase(); b=b.toUpperCase(); return a<b?-1:(a>b?1:0); });
        return {names:names, map:map};
    }

    var psInfo  = collectParaStyles(doc);
    var osInfo  = collectObjectStyles(doc);

    // =============== 选择器 UI ===============
    var LABELS = ["DANGER","WARNING","CAUTION","NOTE","下划线"];
    var w = new Window("dialog", "设置样式与前缀（留空=不插入）");
    w.orientation = "column"; w.alignChildren = ["fill","top"];

    // 段落样式选择
    var pStylePanel = w.add("panel", undefined, "选择段落样式（使用完整路径消除同名歧义）");
    pStylePanel.margins = [10,18,10,10]; pStylePanel.alignChildren = ["fill","top"];

    var rowDanger  = pStylePanel.add("group"); rowDanger.add("statictext", undefined, "DANGER：");
    var ddDanger   = rowDanger.add("dropdownlist", undefined, psInfo.names); ddDanger.selection = 0;

    var rowWarning = pStylePanel.add("group"); rowWarning.add("statictext", undefined, "WARNING：");
    var ddWarning  = rowWarning.add("dropdownlist", undefined, psInfo.names); ddWarning.selection = 0;

    var rowCaution = pStylePanel.add("group"); rowCaution.add("statictext", undefined, "CAUTION：");
    var ddCaution  = rowCaution.add("dropdownlist", undefined, psInfo.names); ddCaution.selection = 0;

    var rowNote    = pStylePanel.add("group"); rowNote.add("statictext", undefined, "NOTE：");
    var ddNote     = rowNote.add("dropdownlist", undefined, psInfo.names); ddNote.selection = 0;

    var rowUnder   = pStylePanel.add("group"); rowUnder.add("statictext", undefined, "下划线（Underline Para Style）：");
    var ddUnder    = rowUnder.add("dropdownlist", undefined, psInfo.names); ddUnder.selection = 0;

    // 尝试智能预选（如果存在这些裸名）
    preselectByName(ddDanger,  "DANGER");
    preselectByName(ddWarning, "WARNING");
    preselectByName(ddCaution, "CAUTION");
    preselectByName(ddNote,    "NOTE");
    preselectByName(ddUnder,   "下划线");

    function preselectByName(dd, bareName){
        for (var i=0; i<dd.items.length; i++){
            var t = dd.items[i].text;
            if (t === bareName || t.match(new RegExp("/" + escapeRegexp(bareName) + "$"))) { dd.selection = i; break; }
        }
    }
    function escapeRegexp(s){ return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }

    // 前缀设置
    var prefixPanel = w.add("panel", undefined, "为不同标题类型设置段首前缀（留空=不插入）");
    prefixPanel.margins = [10,18,10,10];
    var edits = {};
    function addPrefixRow(label){
        var g = prefixPanel.add("group"); g.alignment = ["fill","top"];
        g.add("statictext", undefined, label + "：");
        var et = g.add("edittext", undefined, ""); et.characters = 40;
        edits[label] = et;
    }
    addPrefixRow("DANGER");
    addPrefixRow("WARNING");
    addPrefixRow("CAUTION");
    addPrefixRow("NOTE");
    prefixPanel.add("statictext", undefined, "提示：可输入空格/符号，或粘贴制表符等特殊字符。");

    // 对象样式筛选
    var filterPanel = w.add("panel", undefined, "仅处理对象样式为以下项的“下划线段所在文本框”");
    filterPanel.margins = [10,18,10,10];
    var ddObj = filterPanel.add("dropdownlist", undefined, ["[不筛选]"].concat(osInfo.names));
    ddObj.selection = 0;

    // 按钮
    var gBtns = w.add("group"); gBtns.alignment = ["right","top"];
    var btnCancel = gBtns.add("button", undefined, "取消");
    var btnOK     = gBtns.add("button", undefined, "确定", {name:"ok"});
    btnCancel.onClick = function(){ w.close(0); };
    btnOK.onClick = function(){
        if (!ddDanger.selection || !ddWarning.selection || !ddCaution.selection || !ddNote.selection || !ddUnder.selection) {
            alert("请为五个段落样式全部选择具体样式。"); return;
        }
        w.close(1);
    };
    if (w.show() !== 1) return;

    // 解析对象引用
    var PS_DANGER  = psInfo.map[ddDanger.selection.text];
    var PS_WARNING = psInfo.map[ddWarning.selection.text];
    var PS_CAUTION = psInfo.map[ddCaution.selection.text];
    var PS_NOTE    = psInfo.map[ddNote.selection.text];
    var PS_UNDER   = psInfo.map[ddUnder.selection.text];

    var insertMap = {
        "DANGER" : String(edits["DANGER"].text || ""),
        "WARNING": String(edits["WARNING"].text || ""),
        "CAUTION": String(edits["CAUTION"].text || ""),
        "NOTE"   : String(edits["NOTE"].text || "")
    };

    var filterEnabled = ddObj.selection && ddObj.selection.index > 0;
    var chosenObjStyle = filterEnabled ? osInfo.map[ddObj.selection.text] : null;

    // =============== 主流程：两阶段 + 逆序写入（一次性撤销） ===============
    var totalTitles=0, matched=0, modified=0, skippedSame=0, skippedEmpty=0, skippedByObjStyle=0;
    var missingList = [];
    // 目标：{ story:Story, start:Number, titleTag:String }
    var targets = [];

    app.doScript(function () {
        var stories = doc.stories.everyItem().getElements();

        // 阶段1：扫描并记录
        for (var si=0; si<stories.length; si++) {
            var story = stories[si]; if (!story || !story.isValid) continue;

            var paras = story.paragraphs.everyItem().getElements();
            for (var i=0; i<paras.length; i++) {
                var p = paras[i]; if (!p || !p.isValid) continue;
                var st = p.appliedParagraphStyle;

                var tag = titleTagOf(st);
                if (!tag) continue; // 不是四类标题
                totalTitles++;

                // 找“下划线段”（直到遇到下一个标题）
                var upara = null;
                for (var j=i+1; j<paras.length; j++) {
                    var nxt = paras[j]; if (!nxt || !nxt.isValid) break;
                    var ns = nxt.appliedParagraphStyle;
                    if (titleTagOf(ns)) break; // 下一个标题到了
                    if (ns === PS_UNDER) { upara = nxt; break; }
                }

                if (upara && upara.isValid) {
                    matched++;

                    // 对象样式筛选
                    if (filterEnabled) {
                        var tf = textFrameOf(upara);
                        if (!tf || !tf.isValid || tf.appliedObjectStyle != chosenObjStyle) {
                            skippedByObjStyle++; continue;
                        }
                    }

                    var startIndex = null;
                    try { startIndex = upara.insertionPoints[0].index; } catch(_){}
                    if (startIndex !== null) targets.push({story: story, start: startIndex, titleTag: tag});
                } else {
                    // 缺失
                    missingList.push({ page: pageNameOfParagraph(p), text: preview(p.contents, 80) });
                }
            }
        }

        // 阶段2：按 story / 起始索引降序写入
        targets.sort(function(a,b){
            if (a.story.id !== b.story.id) return a.story.id - b.story.id;
            return b.start - a.start;
        });

        for (var t=0; t<targets.length; t++) {
            var rec = targets[t];
            try {
                if (!rec.story || !rec.story.isValid) continue;
                if (rec.start == null || rec.start < 0 || rec.start >= rec.story.insertionPoints.length) continue;

                var ip = rec.story.insertionPoints[rec.start]; if (!ip || !ip.isValid) continue;
                var para = ip.paragraphs[0]; if (!para || !para.isValid) continue;
                if (para.appliedParagraphStyle !== PS_UNDER) continue; // 再校验

                if (filterEnabled) {
                    var tf = textFrameOf(para);
                    if (!tf || !tf.isValid || tf.appliedObjectStyle != chosenObjStyle) { skippedByObjStyle++; continue; }
                }

                var insertStr = String(insertMap[rec.titleTag] || "");
                if (insertStr.length === 0) { skippedEmpty++; continue; }

                // 已有相同前缀则跳过
                var head = "";
                try {
                    var endIdx = Math.min(rec.start + insertStr.length - 1, rec.story.characters.length - 1);
                    head = (insertStr.length > 0 && endIdx >= rec.start)
                         ? String(rec.story.characters.itemByRange(rec.start, endIdx).contents || "")
                         : "";
                } catch(_){}
                if (head === insertStr) { skippedSame++; continue; }

                ip.contents = insertStr;
                modified++;
            } catch(_){}
        }

        showResult({
            totalTitles: totalTitles, matched: matched, modified: modified,
            skippedSame: skippedSame, skippedEmpty: skippedEmpty, skippedByObjStyle: skippedByObjStyle,
            missingList: missingList, insertMap: insertMap,
            chosenObjStyleName: filterEnabled ? ddObj.selection.text : "[不筛选]"
        });

    }, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, "按选择器插入下划线前缀（稳健）");

    // =============== 辅助函数 ===============
    function titleTagOf(styleObj) {
        if (!styleObj || !styleObj.isValid) return "";
        if (styleObj === PS_DANGER)  return "DANGER";
        if (styleObj === PS_WARNING) return "WARNING";
        if (styleObj === PS_CAUTION) return "CAUTION";
        if (styleObj === PS_NOTE)    return "NOTE";
        return "";
    }
    function textFrameOf(para){
        try {
            var ip = para.insertionPoints[0];
            return (ip && ip.parentTextFrames && ip.parentTextFrames.length>0) ? ip.parentTextFrames[0] : null;
        } catch(_){ return null; }
    }
    function pageNameOfParagraph(para) {
        try {
            var ip = para.insertionPoints[0];
            var tf = ip.parentTextFrames[0];
            var pg = tf.parentPage;
            return (pg && pg.isValid) ? String(pg.name) : "–";
        } catch (_){ return "–"; }
    }
    function preview(s, n) {
        s = (s==null) ? "" : String(s).replace(/\r/g, " / "); n = n||80;
        return (s.length>n) ? (s.substring(0, n-1) + "…") : s;
    }
    function visualize(s) {
        if (s==null) return "(空)"; s=String(s);
        s = s.replace(/\u00A0/g, "⍽").replace(/\t/g, "\\t").replace(/\r/g, "\\r").replace(/ /g, "·");
        return s;
    }
    function showResult(r) {
        var lines = [];
        lines.push("标题总数： " + r.totalTitles);
        lines.push("找到下划线的标题数： " + r.matched);
        lines.push("成功插入： " + r.modified);
        lines.push("已存在相同前缀而跳过： " + r.skippedSame);
        lines.push("因设置为空而跳过： " + r.skippedEmpty);
        lines.push("因对象样式不匹配而跳过： " + r.skippedByObjStyle);
        lines.push("");
        lines.push("对象样式筛选： " + r.chosenObjStyleName);
        lines.push("前缀设置：");
        lines.push("  DANGER ：「" + visualize(r.insertMap.DANGER)  + "」");
        lines.push("  WARNING：「" + visualize(r.insertMap.WARNING) + "」");
        lines.push("  CAUTION：「" + visualize(r.insertMap.CAUTION) + "」");
        lines.push("  NOTE   ：「" + visualize(r.insertMap.NOTE)    + "」");
        lines.push("");
        lines.push("未找到下划线的标题数： " + (r.totalTitles - r.matched));
        if (r.missingList.length>0) {
            lines.push("未配下划线的标题：");
            for (var j=0;j<r.missingList.length;j++){
                lines.push("P" + r.missingList[j].page + "： " + r.missingList[j].text);
            }
        } else {
            lines.push("全部通过 ✅");
        }

        var w = new Window("dialog", "检查与插入结果");
        w.orientation = "column"; w.alignChildren = ["fill","top"];
        var et = w.add("edittext", undefined, lines.join("\r"), {multiline:true, scrolling:true});
        et.preferredSize = [740, 460];
        var g = w.add("group"); g.alignment = ["right","top"];
        g.add("button", undefined, "确定", {name:"ok"});
        w.center(); w.show();
    }
})();
